﻿using DM_Sqlite.MappingClass;
using DM_TOOLS.Tools;
using DM_TOOLS.Tools.SMTP;
using DMSystem_Sqlite_WebAPI.Utility;
using DMSystem_Sqlite_WebAPI.Utility.Feishu;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;
using Quartz;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DMSystem_Sqlite_WebAPI.Utility.Quartz
{
    public class MyJob : IJob
    {
        private readonly ILogger<MyJob> _logger;
        private readonly IMemoryCache _memoryCache;//内存缓存
        private readonly IHubContext<SiginalrHub> _hubContext;//signalr
        public MyJob(ILogger<MyJob> logger, IMemoryCache memoryCache, IHubContext<SiginalrHub> hubContext)
        {
            _logger = logger;
            _memoryCache = memoryCache;
            _hubContext = hubContext;
        }
        public async Task Execute(IJobExecutionContext context)
        {
            var map = context.JobDetail.JobDataMap;
            string? path = map.GetString("datapath");
            try
            {
                Console.WriteLine($"{path} in {Thread.CurrentThread.ManagedThreadId} run at {DateTime.Now}");
                var userprop = _memoryCache.Get<dm_props_user>(path);
                var adminprop = _memoryCache.Get<dm_props_admin>("datamonitoradminpara");
                //获得当天日期文件夹路径
                string watchpath = Path.Combine(path, DateTime.Now.ToString("MM_dd"));
                //获得最新的csv文件
                var file = FileOperator.GetExtensionFiles(watchpath, "csv").LastOrDefault();
                //获得缓存里的文件名
                var lastfilename = _memoryCache.Get<string>(path + "filename");
                //比较最新产生的文件名是否跟缓存里的一样，一样说明没有新文件产生
                if (file != null)
                {
                    if (file.Name != lastfilename)
                    {
                        if (userprop != null && adminprop != null)
                        {
                            //最新文件名存入缓存中
                            await Console.Out.WriteLineAsync($"监控到新文件{file.Name}");
                            _memoryCache.Set<string>(path + "filename", file.Name);

                            var structall = await CSVFileWatch.CSVFileWatchCSVAsyncV2(file.FullName, file.Name, adminprop.reducetimes);
                            switch (structall.status)
                            {
                                case 0:
                                    var lastingtime = adminprop.points / adminprop.sample;//csv文件的持续时间
                                    var spdidx = structall.headers.IndexOf("spd");
                                    List<double> spd = new List<double>();
                                    double spdavg = 0;//平均速度
                                    double sumdistance = 0;//单个文件的里程数
                                    if (spdidx != -1)
                                    {
                                        spd = structall.alldatalist[structall.headers.IndexOf("spd")];
                                        spdavg = await CSVFileWatch.CalSpdAverageAsync(spd);
                                        sumdistance = Math.Round(spdavg / 3600 * lastingtime, 2);
                                    }
                                    //帅选出lat，lon只需要第一个点和最后一个点，还有其他图表里的数据
                                    var chartall = await CSVFileWatch.CSVFileWatchStructEditAsync(structall, userprop);//图表数据

                                    //获得缓存里的日期，就是监控开始的日期
                                    var datetime = _memoryCache.Get<DateTime>(userprop.watchpath + "datetime");
                                    //获得当前日期
                                    var nowtime = DateTime.Now;
                                    //获得他们之间的日期差，并把这些中间的日期的缓存清除掉
                                    var datespan = DateTimeOperator.GetDateStringsBetweenDates(datetime, nowtime);
                                    for (int i = 0; i < datespan.Length; i++)
                                    {
                                        _memoryCache.Remove(userprop.vehicle + datespan[i] + "sumdistance");
                                        _memoryCache.Remove(userprop.vehicle + datespan[i] + "filecount");
                                        _memoryCache.Remove(userprop.vehicle + datespan[i] + "readfilecount");
                                        _memoryCache.Remove(userprop.vehicle + datespan[i] + "chanerrorcount");
                                        _memoryCache.Remove(userprop.vehicle + datespan[i] + "readgpsfilecount");
                                        _memoryCache.Remove(userprop.vehicle + datespan[i] + "gpserrorcount");
                                    }

                                    //获得缓存里前一次的累计里程，这里需要用到GetOrCreate，因为过了一天日期就不同了，需要重新创建累计里程缓存
                                    var lastsumdis = _memoryCache.GetOrCreate<double>(userprop.vehicle + DateTime.Now.ToString("MM-dd") + "sumdistance", value =>
                                    {
                                        return 0;
                                    });
                                    //标识监控到的数据的总数
                                    var filecount = _memoryCache.GetOrCreate<int>(userprop.vehicle + DateTime.Now.ToString("MM-dd") + "filecount", value =>
                                    {
                                        return 0;
                                    });
                                    //标识一旦监控到-1的异常，则启动此跟踪值并置1，如没有异常则如filecount正常自增
                                    var readfilecount = _memoryCache.GetOrCreate<int>(userprop.vehicle + DateTime.Now.ToString("MM-dd") + "readfilecount", value =>
                                    {
                                        return 0;
                                    });
                                    //标识一旦监控到错误gps的异常，则启动此跟踪值并置1，如没有异常则如filecount正常自增
                                    var readgpsfilecount = _memoryCache.GetOrCreate<int>(userprop.vehicle + DateTime.Now.ToString("MM-dd") + "readgpsfilecount", value =>
                                    {
                                        return 0;
                                    });
                                    //设置缓存里这一次的累计里程和文件数
                                    _memoryCache.Set<double>(userprop.vehicle + DateTime.Now.ToString("MM-dd") + "sumdistance", lastsumdis + sumdistance);
                                    _memoryCache.Set<int>(userprop.vehicle + DateTime.Now.ToString("MM-dd") + "filecount", filecount + 1);
                                    _memoryCache.Set<int>(userprop.vehicle + DateTime.Now.ToString("MM-dd") + "readfilecount", readfilecount + 1);
                                    _memoryCache.Set<int>(userprop.vehicle + DateTime.Now.ToString("MM-dd") + "readgpsfilecount", readgpsfilecount + 1);
                                    var sdsent = _memoryCache.Get<double>(userprop.vehicle + DateTime.Now.ToString("MM-dd") + "sumdistance");
                                    var countsent = _memoryCache.Get<int>(userprop.vehicle + DateTime.Now.ToString("MM-dd") + "filecount");
                                    var countread = _memoryCache.Get<int>(userprop.vehicle + DateTime.Now.ToString("MM-dd") + "readfilecount");
                                    var gpscountread = _memoryCache.Get<int>(userprop.vehicle + DateTime.Now.ToString("MM-dd") + "readgpsfilecount");
                                    var mailconfig = _memoryCache.Get<SMTPConfig>(userprop.vehicle + "mailconfig");
                                    #region 开始发送数据
                                    if (chartall.Count > 2)
                                    {
                                        foreach (var i in SiginalrHub.user)
                                        {
                                            await _hubContext.Clients.Group(i).SendAsync("csvfileinfo", chartall, structall.name, spdavg, sdsent, countsent, userprop.watchpath);
                                        }
                                        var idx = await chartall.FindNegativeOneAsync();
                                        //说明有通道有-1问题
                                        if (idx != -1)
                                        {
                                            //标识-1出现的文件数量
                                            var errorcount = _memoryCache.GetOrCreate<int>(userprop.vehicle + DateTime.Now.ToString("MM-dd") + "chanerrorcount", value =>
                                            {
                                                return 0;
                                            });
                                            _memoryCache.Set(userprop.vehicle + DateTime.Now.ToString("MM-dd") + "chanerrorcount", errorcount + 1);
                                            //获得实际的-1文件数量
                                            var errorcountfile = _memoryCache.Get<int>(userprop.vehicle + DateTime.Now.ToString("MM-dd") + "chanerrorcount");
                                            //第一次出现-1时就把readfilecount置1，后面再出现-1就不会置1了
                                            if (errorcountfile == 1)
                                            {
                                                //一旦监控到-1的异常，则启动此跟踪值并置1，与errorcountfile一致
                                                _memoryCache.Set<int>(userprop.vehicle + DateTime.Now.ToString("MM-dd") + "readfilecount", 1);
                                            }
                                            //当-1文件数达到120个，说明至少有10分钟了，但不确定是否连续-1
                                            if (errorcountfile > 120)
                                            {
                                                //说明-1错误一直持续了120个
                                                if (errorcountfile == countread)
                                                {
                                                    //await FeishuRobot.SendFeishuMessage("车号：" + userprop.vehicle + "-" + userprop.ip + "(" + userprop.remarks + ")：启动有通道连续10分钟出现-1。最后文件名为：" + file.Name);
                                                    await FeishuRobot.SendFeishuMessage($"车号：{userprop.vehicle}-{userprop.ip}-{userprop.remarks}: 启动{structall.headers[idx]}通道连续10分钟出现-1。最后文件名为：{file.Name}");
                                                    _memoryCache.Set<int>(userprop.vehicle + DateTime.Now.ToString("MM-dd") + "readfilecount", 0);
                                                    _memoryCache.Set<int>(userprop.vehicle + DateTime.Now.ToString("MM-dd") + "chanerrorcount", 0);
                                                }
                                                //说明-1的数量小于监控到的数量，表明出现-1不连续，则不会发飞书
                                                else
                                                {
                                                    _memoryCache.Set<int>(userprop.vehicle + DateTime.Now.ToString("MM-dd") + "readfilecount", 0);
                                                    _memoryCache.Set<int>(userprop.vehicle + DateTime.Now.ToString("MM-dd") + "chanerrorcount", 0);
                                                }
                                            }
                                        }
                                    }
                                    //处理经纬度的异常
                                    else
                                    {
                                        _logger.LogWarning("车号：" + userprop.vehicle + "-" + userprop.ip + "(" + userprop.remarks + ")：经纬度为0或通道名没有匹配上。最后文件名为：" + file.Name);
                                        //标识GPS出现error的文件数量
                                        var gpserrorcount = _memoryCache.GetOrCreate<int>(userprop.vehicle + DateTime.Now.ToString("MM-dd") + "gpserrorcount", value =>
                                        {
                                            return 0;
                                        });
                                        _memoryCache.Set(userprop.vehicle + DateTime.Now.ToString("MM-dd") + "gpserrorcount", gpserrorcount + 1);
                                        //获得实际的错误gps文件数量
                                        var gpserrorcountfile = _memoryCache.Get<int>(userprop.vehicle + DateTime.Now.ToString("MM-dd") + "gpserrorcount");

                                        if (gpserrorcountfile == 1)
                                        {
                                            //一旦监控到错误gps的异常，则启动此跟踪值并置1，与errorcountfile一致
                                            _memoryCache.Set<int>(userprop.vehicle + DateTime.Now.ToString("MM-dd") + "readgpsfilecount", 1);
                                        }
                                        //当-1文件数达到120个，说明至少有10分钟了，但不确定是否连续-1
                                        if (gpserrorcountfile > 120)
                                        {
                                            //说明gps错误一直持续了120个
                                            if (gpserrorcountfile == gpscountread)
                                            {
                                                //await FeishuRobot.SendFeishuMessage("车号：" + userprop.vehicle + "-" + userprop.ip + "(" + userprop.remarks + ")：经纬度为0或通道名没有匹配上持续10分钟。最后文件名为：" + file.Name);
                                                await FeishuRobot.SendFeishuMessage($"车号：{userprop.vehicle}-{userprop.ip}-{userprop.remarks}: 经纬度为0或通道名没有匹配上持续10分钟。最后文件名为：{file.Name}");
                                                _memoryCache.Set<int>(userprop.vehicle + DateTime.Now.ToString("MM-dd") + "readgpsfilecount", 0);
                                                _memoryCache.Set<int>(userprop.vehicle + DateTime.Now.ToString("MM-dd") + "gpserrorcount", 0);
                                            }
                                            //说明gps错误的数量小于监控到的数量，表明出现gps错误不连续
                                            else
                                            {
                                                _memoryCache.Set<int>(userprop.vehicle + DateTime.Now.ToString("MM-dd") + "readgpsfilecount", 0);
                                                _memoryCache.Set<int>(userprop.vehicle + DateTime.Now.ToString("MM-dd") + "gpserrorcount", 0);
                                            }
                                        }
                                    }
                                    //处理加速度或位移是否有超标值，有就发，可以持续发
                                    var res = SMTPWarnContent.CreateWarnContent(structall, userprop.vehicle, adminprop.accerrorvalue, adminprop.diserrorvalue, userprop.frontdis, userprop.reardis);
                                    //先判断有没有异常，没有就不用费劲去看字典了
                                    if (res != "")
                                    {
                                        //先获得mailconfig缓存
                                        if (mailconfig != null)
                                        {
                                            //再从缓存里看有没有mailerror，如果没有说明第一次碰到error
                                            var firstmailerror = _memoryCache.Get<string>(userprop.vehicle + "mailerror");
                                            if (firstmailerror == null)
                                            {
                                                //第一次碰到错误发送邮件
                                                //await SMTPMail.SendEmailAsync(mailconfig, res);
                                                await FeishuRobot.SendFeishuMessage("车号：" + userprop.vehicle + "-" + userprop.ip + "(" + userprop.remarks + ")" + "通道可能损坏：" + res + "。文件名为：" + file.Name);
                                                //如果第一次碰到，则创建缓存并设置为第一次的错误信息
                                                var mailerror = _memoryCache.GetOrCreate<string>(userprop.vehicle + "mailerror", value =>
                                                {
                                                    return res;
                                                });
                                                //再创建缓存记录第一次发送的时间
                                                var starttime = _memoryCache.GetOrCreate<DateTime>(userprop.vehicle + "sendtime", value =>
                                                {
                                                    return DateTime.Now;
                                                });
                                            }
                                            //说明缓存里已经有mailerror了，不是第一次出现问题了
                                            else
                                            {
                                                //判断当前的与上一次的是否问题一致，不一致再发邮件，再覆盖记录发送时间
                                                if (res != firstmailerror)
                                                {
                                                    _memoryCache.Set<string>(userprop.vehicle + "mailerror", res);
                                                    //await SMTPMail.SendEmailAsync(mailconfig, res);
                                                    await FeishuRobot.SendFeishuMessage("车号：" + userprop.vehicle + "-" + userprop.ip + "(" + userprop.remarks + ")" + "通道可能损坏：" + res + "。文件名为：" + file.Name);

                                                    _memoryCache.Set<DateTime>(userprop.vehicle + "sendtime", DateTime.Now);
                                                }
                                                //如果一致，则判断是否经过了1小时，然后再发送邮件提醒
                                                else
                                                {
                                                    //先获取上一次缓存里的发送时间
                                                    var lastsendtime = _memoryCache.Get<DateTime>(userprop.vehicle + "sendtime");
                                                    if (SMTPWarnContent.IsPastOneHour(lastsendtime, mailconfig.emailtimespan))
                                                    {
                                                        //await SMTPMail.SendEmailAsync(mailconfig, res);
                                                        await FeishuRobot.SendFeishuMessage("车号：" + userprop.vehicle + "-" + userprop.ip + "(" + userprop.remarks + ")" + "通道可能损坏：" + res + "。文件名为：" + file.Name);
                                                        _memoryCache.Set<DateTime>(userprop.vehicle + "sendtime", DateTime.Now);
                                                    }
                                                }
                                            }
                                        }
                                    }
                                    #endregion
                                    break;
                                case 1:
                                    _logger.LogWarning($"{userprop.vehicle}的{file.Name}文件有空值或nan");
                                    break;
                                case 2:
                                    _logger.LogWarning($"{userprop.vehicle}的{file.Name}文件大小为0kb");
                                    break;
                                case 3:
                                    _logger.LogWarning($"{userprop.vehicle}的{file.Name}文件被占用");
                                    break;
                                case 9:
                                    _logger.LogWarning($"{userprop.vehicle}的{file.Name}文件读取错误，请查看错误日志");
                                    break;
                            }

                        }

                    }
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.Message);
                foreach (var i in SiginalrHub.user)
                {
                    await _hubContext.Clients.Group(i).SendAsync("csvexception", path, ex.Message);
                }
            }
           
        }
    }
}
